package com.briup.es.service.impl;

import com.briup.es.config.auth.TokenMap;
import com.briup.es.config.auth.UserDetails;
import com.briup.es.config.response.ResultCode;
import com.briup.es.domain.bean.User;
import com.briup.es.domain.dto.LoginDto;
import com.briup.es.domain.dto.RegisterUserDto;
import com.briup.es.domain.dto.UpdatePasswordDto;
import com.briup.es.domain.dto.UpdateUserDto;
import com.briup.es.mapper.UserMapper;
import com.briup.es.service.UserService;
import com.briup.es.utils.AssertUtil;
import com.briup.es.utils.BeanUtil;
import com.briup.es.utils.JwtUtil;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Service
public class UserServiceImpl implements UserService {
    @Resource
    private UserMapper userMapper;

    @Override
    public Map<String, Object> login(LoginDto loginDto) {
        String username = loginDto.getUsername();
        String password = loginDto.getPassword();
        // 校验用户名是否存在，从数据库中根据用户名查询用户信息
        User user = userMapper.queryByUsername(username);
        // 校验用户是否存在，如果用户不存在抛出异常 显示用户不存在
        AssertUtil.requiredNotNull(user,
                ResultCode.USER_IS_NOT_EXISTS);

        // 如果用户存在，继续比较用户输入的密码是否正确
        AssertUtil.isTrue(password.equals(user.getPassword()),
                ResultCode.PASSWORD_IS_ERROR);

        // 如果用户输入的密码正确，那么进一步比较该用户账号是否可用
        AssertUtil.isTrue(0 == user.getStatus(),
                ResultCode.USER_IS_UNABLE);

        // 如果账户可用，说明登录成功，需要进一步给用户签发登录成功的凭证
        // 将登录成功的用户id及用户名存入Map集合中
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", user.getId());
        claims.put("username", user.getUsername());
        // 根据上述数据，给当前登录用户签发token
        String token = JwtUtil.sign(claims);

        // 将token信息，以及当前登录用户的信息，存入Map集合中，返回给用户
        claims.clear();
        claims.put("jwt", token);
        claims.put("userInfo", user);

        // 将生成的token放入到tokenMap中
        TokenMap.set(user.getId(), token);

        return claims;
    }

    @Override
    public User queryById(Integer userId) {
        // 校验用户id参数是否可用，如果不可用抛出 该用户不存在的异常
        AssertUtil.isTrue(userId != null && userId > 0,
                ResultCode.USER_IS_NOT_EXISTS);

        return userMapper.queryById(userId);
    }

    @SneakyThrows
    @Override
    public void register(RegisterUserDto userDto) {
        // 校验该用户名是否存在，如果用户存在则无法注册
        User userForDB = userMapper.queryByUsername(userDto.getUsername());
        AssertUtil.requiredNull(userForDB, ResultCode.USER_IS_EXISTS);

        // 将userDto对象内容，拷贝到User类对象中
        User user = BeanUtil.bean2VO(userDto, User.class);
        // 设置注册时间
        user.setRegisterTime(LocalDateTime.now());
        // 将用户对象中的数据存储到数据库中
        userMapper.addUser(user);
    }

    @Override
    public void updateUser(UpdateUserDto userDto) {
        // 修改数据时，可以修改用户名，但是必须保障新的用户名未被使用过
        User user = userMapper.queryByUsername(userDto.getUsername());
        // 根据用户名查询用户数据，如果用户对象不为null，
        // 或id与你传入的用户id不相同，那么抛出用户名已被占用的错误
        AssertUtil.isTrue(user == null || Objects.equals(user.getId(), userDto.getId()),
                ResultCode.USERNAME_IS_USED);

        // 如果用户名未被其他用户占用，那么继续修改
        userMapper.updateUser(userDto);
    }

    @Override
    public void updatePassword(UpdatePasswordDto passwordDto) {
        // 明确修改谁的密码？当前登录用户
        User user = UserDetails.currentUser();
        // 比较数据库中存储的密码与用户输入的初始密码，两者必须一致
        AssertUtil.isTrue(user.getPassword().equals(passwordDto.getOldPassword()),
                ResultCode.OLD_PASSWORD_IS_ERROR);
        // 修改密码
        userMapper.updatePassword(user.getId(), passwordDto.getNewPassword());
        // 密码修改成功后，应该退出当前登录状态，即将服务器中的token清除
        TokenMap.remove(user.getId());
    }
}

